#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/delay.h>

//SD card
#include <string.h>
#include <avr/pgmspace.h>
#include <avr/sleep.h>
#include "fat.h"
#include "fat_config.h"
#include "partition.h"
#include "sd_raw.h"
#include "sd_raw_config.h"


#define DEBUG 1

typedef enum
{
	preflight,
	ascent,
	heating,
	cooling,
	shutdown
} STATES;

enum NETWORK_ID
{
	MESSAGE_OK		= 0b00000001,
	MESSAGE_ERROR	= 0b00000010,
	MESSAGE_DATA	= 0b00000100,
	MESSAGE_EVENT	= 0b00001000,
	MESSAGE_STAGE	= 0b00010000,
	MESSAGE_BATTERY = 0b00100000
};

//uint8_t resetAVR = 0;
uint8_t clearSDcard = 0;
uint8_t armStatus = 0;
uint8_t eventID[1];
uint8_t runMainLoop = 0;				//Set to one when Main loop should run
uint8_t runBatteryCheck = 0;
uint8_t runSendOK = 0;
uint8_t dataReceived = 0;
uint8_t stateChanged = 0;
uint16_t timerCounter16bit = 0;
uint8_t state = preflight;
uint16_t SaveSDCardCounter = 0;

void MainLoop()
{
	cli();
	char sensorData[12];
	uint8_t i = 0;
	while (i!=12)
	{
		sensorData[i] = 0;
		i++;
	}
	//Read temperature data
	uint16_t pressureChamberTemperature = getPressureChamberTemperature();
	sensorData[0] = pressureChamberTemperature / 256;
	sensorData[1] = pressureChamberTemperature;
	uint16_t vacuumChamberTemperature = getVacuumChamberTemperature();
	sensorData[2] = vacuumChamberTemperature / 256;
	sensorData[3] = vacuumChamberTemperature;
	
	//Read pressure data
	uint16_t pressureChamberPressure = getPressureChamberPressure();
	sensorData[4] = pressureChamberPressure / 256;
	sensorData[5] = pressureChamberPressure;
	uint16_t vacuumChamberPressure = getVacuumChamberPressure();
	sensorData[6] = vacuumChamberPressure / 256;
	sensorData[7] = vacuumChamberPressure;
	
	//Read resistance wire data
	uint16_t resistanceWireVoltagePressureChamber = getResistanceWireVoltagePressureChamber();
	sensorData[8] = resistanceWireVoltagePressureChamber / 256;
	sensorData[9] = resistanceWireVoltagePressureChamber;
	uint16_t resistanceWireVoltageVacuumChamber = getResistanceWireVoltageVacuumChamber();
	sensorData[10] = resistanceWireVoltageVacuumChamber / 256;
	sensorData[11] = resistanceWireVoltageVacuumChamber;
	
	uint16_t timer = getTimer();
	uint16_t timerCounter = getTimerCounter();
	uint8_t currentstate = getStage();

	//Store on SD-card
	SDCard2(sensorData,timer,timerCounter,currentstate);
	//Read battery voltage every loop, every 10mins has to go elsewhere (in preflight stage)
	UART_SEND(MESSAGE_DATA,&sensorData[0],12,timer,timerCounter);
	sei();
}

void SendOK()
{
	UART_SEND(MESSAGE_OK,0,0);
}

void BatteryCheck()		//Battery voltage pre launch (should be changed to once every x minutes)
{
	cli();
	char sensorData[4];
	uint8_t i = 0;
	while (i!=4)
	{
		sensorData[i] = 0;
		i++;
	}
	PORTD |= (1<<PIND6);
	uint16_t battery1Voltage = getBattery1Voltage();
	sensorData[0] = battery1Voltage / 256;
	sensorData[1] = battery1Voltage;
	uint16_t battery2Voltage = getBattery2Voltage();
	sensorData[2] = battery2Voltage / 256;
	sensorData[3] = battery2Voltage;
	PORTD &= ~(1<<PIND6);

	uint16_t timer = getTimer();
	uint16_t timerCounter = getTimerCounter();
	uint8_t currentstate = getStage();
	
	//Store on SD-card
	SDCard2(sensorData,timer,timerCounter,currentstate);
	
	UART_SEND(MESSAGE_BATTERY,&sensorData[0],4);
	sei();
}
int main(void)
{
	cli();
	WDT_off();
	WDT_Init();
	Initialize();
	SDcard();
	//Seek last SD message
	SDcardBackup();
	sei();
	
	while(1)
    {
		reset_wdt();
		if (stateChanged == 1)
		{
			char tempState[1];
			tempState[0] = getStage();
			UART_SEND(MESSAGE_STAGE, &tempState[0], 1);
			stateChanged = 0;
		}
		if (runMainLoop == 1)
		{
			MainLoop();	
			runMainLoop = 0;
		}
		if (runSendOK == 1)
		{
			SendOK();
			runSendOK = 0;
		}
		if (runBatteryCheck == 1)
		{
			BatteryCheck();
			runBatteryCheck = 0;
		}
		if (dataReceived == 1)
		{
			lookForNetworkMessage();
		}
    }
}

void resetAVR()
{
		uint8_t temp[1];
		temp[0] = 3;
		UART_SEND(MESSAGE_EVENT,&temp,1);
		while(1)
		{
		
		}
}

/*
	Initializes the components used and enables global interrupts. Also sets input/output pins
	initUSART:
		Enables transmission and reception, must be placed first for debug purposes
	initADC:
		-----
	inittimer:
		-----
	WDT_Init:
		-----
*/
void Initialize()
{
		initUSART();					//Sets up transmission and reception using UART
		initADC();						//Initializes ADC
		inittimer();					//Sets up timers
		
		//sei();							//Enable global interrupts
		
		//All unused pins should be set so internal pull-up is activated!
		
		//Input
		DDRB &= ~(1 << PINB2);				//LO signal
		
		//Output
		DDRD |= (1 << PIND6);			//Battery switch value measurements pre flight
		DDRD |= (1 << PIND7);			//Multiplexer A0
		DDRB |= (1 << PINB0);			//Multiplexer A1
		DDRB |= (1 << PINB1);			//Multiplexer A2
		
		DDRB |= 1 << PINB6;				//Battery switch 1
		DDRB |= 1 << PINB7;				//Battery switch 2
}

void setArmed()
{
	armStatus = 1;
	eventID[0] = 1;
	UART_SEND(MESSAGE_EVENT,&eventID,1);
}

void clearArmed()
{
	armStatus = 0;
	eventID[0] = 2;
	UART_SEND(MESSAGE_EVENT,&eventID,1);
}

uint8_t getArmedStatus()
{
	return armStatus;
}

void SDcard()
	{
		/*we will just use ordinary idle mode */
		set_sleep_mode(SLEEP_MODE_IDLE);


			/* setup sd card slot */
			if(!sd_raw_init())
			{
	#if DEBUG
				//uart_puts_p(PSTR("MMC/SD initialization failed\n"));
	#endif
			}
	}
		
void SDCard2(char sData[12],uint16_t timer,uint16_t timerCounter,uint8_t currentstate)			
	{
			/* open first partition */
			struct partition_struct* partition = partition_open(sd_raw_read,
																sd_raw_read_interval,
	#if SD_RAW_WRITE_SUPPORT
																sd_raw_write,
																sd_raw_write_interval,
	#else
																0,
																0,
	#endif
																0
															   );

			if(!partition)
			{
				/* If the partition did not open, assume the storage device
				 * is a "superfloppy", i.e. has no MBR.
				 */
				partition = partition_open(sd_raw_read,
										   sd_raw_read_interval,
	#if SD_RAW_WRITE_SUPPORT
										   sd_raw_write,
										   sd_raw_write_interval,
	#else
										   0,
										   0,
	#endif
										   -1
										  );
				/*if(!partition)
				{
	#if DEBUG
					uart_puts_p(PSTR("opening partition failed\n"));
	#endif
					continue;
				}*/
			}
		
			/* open file system */
			struct fat_fs_struct* fs = fat_open(partition);
			/*if(!fs)
			{
				#if DEBUG
				uart_puts_p(PSTR("opening filesystem failed\n"));
				#endif
				continue;
			}*/
		
			/* open root directory */
			struct fat_dir_entry_struct directory;
			fat_get_dir_entry_of_path(fs, "/", &directory);

			struct fat_dir_struct* dd = fat_open_dir(fs, &directory);
			/*if(!dd)
			{
				#if DEBUG
				uart_puts_p(PSTR("opening root directory failed\n"));
				#endif
				continue;
			}*/
			
			struct fat_dir_entry_struct file_entry;
			fat_create_file(dd, "data.txt", &file_entry);
			

				
// 			SaveSDCardCounter++;
// 			uint8_t filename;
// 			uint8_t existingFile = fat_create_file(dd, "save1", &file_entry);
// 			if (SaveSDCardCounter > 100)
// 			{
// 				uint8_t SDCardFileNumber;		
// 				while (existingFile == 2)
// 				{
// 					const char base[] = "save";
// 					char filename [10];
// 					sprintf(filename, "%s%d.txt", base, SDCardFileNumber);
// 					printf("filename = \"%s\"\n", filename);
// 					existingFile = fat_create_file(dd, filename, &file_entry);
// 					SDCardFileNumber++;
// 				}
// 				SaveSDCardCounter = 0;
// 			}				
		
			struct fat_file_struct* fd = fat_open_file(fs, &file_entry);
		
			int32_t file_pos = 0;
			fat_seek_file(fd, &file_pos, FAT_SEEK_END);
			
			/*file_pos = 0;

			if(!fat_seek_file(fd, &file_pos, FAT_SEEK_CUR));

			{

			 // error

			}

			// file_pos now contains the absolute file position*/
			
 			char tempArray[1];
 			char timeStamp[2];		
 			timeStamp[0] = timer/256;

 			timeStamp[1] = timer;
 			tempArray[0] = timerCounter;
			   		
			char buffer[80]; //54
			//memset(buffer, 0, sizeof(buffer));
			int n;

			if (state == preflight)
			{
				n = sprintf(buffer,"S.%d.%d.%d.%d.%d.%d.%d.E\r\n",tempArray[0],timeStamp[0],timeStamp[1],sData[0],sData[1],sData[2],sData[3]);
			}
			else
			{
				n = sprintf(buffer,"S.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.E\r\n",tempArray[0],timeStamp[0],timeStamp[1],sData[0],sData[1],sData[2],sData[3],
				sData[4],sData[5],sData[6],sData[7],sData[8],sData[9],sData[10],sData[11]);
			}
			
			/*int write = */fat_write_file(fd, buffer, n);
			
// 						if (write < 0)
// 						{
// 							state = ascent;
// 						}
// 						else if (write > 0)
// 						{
// 							state = heating;
// 							timerCounter16bit = 35;
// 							TCNT1 = 0;					//(remember to change in timer.c  as well!)
// 						}
// 						else if (write == 0)
// 						{
// 							state = cooling;
// 						}
// 						else
// 						{
// 							state = shutdown;
// 						}
			
			file_pos = 0;
			fat_seek_file(fd, &file_pos, FAT_SEEK_END);
			
			file_pos = 0;

			if(!fat_seek_file(fd, &file_pos, FAT_SEEK_CUR))

			{

				// error

			}

			// file_pos now contains the absolute file position	
		
			fat_close_file(fd);
			
			struct fat_dir_entry_struct file_entry_stage;			
			fat_create_file(dd, "stage.txt", &file_entry_stage);
			
			struct fat_file_struct* fd_stage = fat_open_file(fs, &file_entry_stage);
		
			int32_t file_pos_stage = 0;
			fat_seek_file(fd_stage, &file_pos_stage, FAT_SEEK_SET);
			   	
			char buffer_stage[80]; //54
			//memset(buffer_stage, 0, sizeof(buffer_stage));
			int n_stage;

			n_stage = sprintf(buffer_stage,"%d.%d.%d.%d.END",tempArray[0],timeStamp[0],timeStamp[1],currentstate);
			
			fat_write_file(fd_stage, buffer_stage, n_stage);
			
// 										if (write == -1)
// 										{
// 											state = shutdown;
// 										}
// 										else if (write == 80)
// 										{
// 											state = heating;
// 											timerCounter16bit = 8;
// 											TCNT1 = 0;					//(remember to change in timer.c  as well!)
// 										}
// 										else
// 										{
// 											state = ascent;
// 										}											
										
			
			file_pos_stage = 0;
			fat_seek_file(fd_stage, &file_pos_stage, FAT_SEEK_END);
			
			file_pos_stage = 0;

			if(!fat_seek_file(fd_stage, &file_pos_stage, FAT_SEEK_CUR))

			{

				// error

			}

			// file_pos now contains the absolute file position	
		
			fat_close_file(fd_stage);
		
		/* close directory */
		fat_close_dir(dd);

		/* close file system */
		fat_close(fs);

		/* close partition */
		partition_close(partition);  
		return 0;
	}
	
void SDClear(int clearType)
{
	


			/* open first partition */
			struct partition_struct* partition = partition_open(sd_raw_read,
																sd_raw_read_interval,
	#if SD_RAW_WRITE_SUPPORT
																sd_raw_write,
																sd_raw_write_interval,
	#else
																0,
																0,
	#endif
																0
															   );

			if(!partition)
			{
				/* If the partition did not open, assume the storage device
				 * is a "superfloppy", i.e. has no MBR.
				 */
				partition = partition_open(sd_raw_read,
										   sd_raw_read_interval,
	#if SD_RAW_WRITE_SUPPORT
										   sd_raw_write,
										   sd_raw_write_interval,
	#else
										   0,
										   0,
	#endif
										   -1
										  );
				/*if(!partition)
				{
	#if DEBUG
					uart_puts_p(PSTR("opening partition failed\n"));
	#endif
					continue;
				}*/
			}
		
			/* open file system */
			struct fat_fs_struct* fs = fat_open(partition);
			/*if(!fs)
			{
				#if DEBUG
				uart_puts_p(PSTR("opening filesystem failed\n"));
				#endif
				continue;
			}*/
		
			/* open root directory */
			struct fat_dir_entry_struct directory;
			fat_get_dir_entry_of_path(fs, "/", &directory);

			struct fat_dir_struct* dd = fat_open_dir(fs, &directory);
			
				struct fat_dir_entry_struct file_entry_stage;
				
				if (clearType == 1)
				{
					fat_create_file(dd, "data.txt", &file_entry_stage);
					fat_delete_file(fs, &file_entry_stage);
					
					uint8_t temp[1];
					temp[0] = 5;
					UART_SEND(MESSAGE_EVENT,&temp,1);
				}				
				fat_create_file(dd, "stage.txt", &file_entry_stage);
				fat_delete_file(fs, &file_entry_stage);
				
				uint8_t temp[1];
				temp[0] = 128;
				UART_SEND(MESSAGE_EVENT,&temp,1);
			
		/* close directory */
		fat_close_dir(dd);

		/* close file system */
		fat_close(fs);

		/* close partition */
		partition_close(partition);
		return 0;				
}	
	

void SDcardBackup()			
	{
			/* open first partition */
			struct partition_struct* partition = partition_open(sd_raw_read,
																sd_raw_read_interval,
	#if SD_RAW_WRITE_SUPPORT
																sd_raw_write,
																sd_raw_write_interval,
	#else
																0,
																0,
	#endif
																0
															   );

			if(!partition)
			{
				/* If the partition did not open, assume the storage device
				 * is a "superfloppy", i.e. has no MBR.
				 */
				partition = partition_open(sd_raw_read,
										   sd_raw_read_interval,
	#if SD_RAW_WRITE_SUPPORT
										   sd_raw_write,
										   sd_raw_write_interval,
	#else
										   0,
										   0,
	#endif
										   -1
										  );
				/*if(!partition)
				{
	#if DEBUG
					uart_puts_p(PSTR("opening partition failed\n"));
	#endif
					continue;
				}*/
			}
		
			/* open file system */
			struct fat_fs_struct* fs = fat_open(partition);
			/*if(!fs)
			{
				#if DEBUG
				uart_puts_p(PSTR("opening filesystem failed\n"));
				#endif
				continue;
			}*/
		
			/* open root directory */
			struct fat_dir_entry_struct directory;
			fat_get_dir_entry_of_path(fs, "/", &directory);

			struct fat_dir_struct* dd = fat_open_dir(fs, &directory);
			/*if(!dd)
			{
				#if DEBUG
				uart_puts_p(PSTR("opening root directory failed\n"));
				#endif
				continue;
			}*/
			
			struct fat_dir_entry_struct file_entry;
			fat_create_file(dd, "stage.txt", &file_entry);
		
			struct fat_file_struct* fd = fat_open_file(fs, &file_entry);
		
			int32_t file_pos = 0;
			fat_seek_file(fd, &file_pos, FAT_SEEK_SET);
			
		    char read_buffer[20];
		    //memset(read_buffer, 0, sizeof(read_buffer));
		    fat_read_file(fd, read_buffer, 20);
			
			int k = 0;
			int temporary[5];
			temporary[0] = 0;
			temporary[1] = 0;
			temporary[2] = 0;
			temporary[3] = 0;
			temporary[4] = 0;
			//memset(temporary, 0, sizeof(temporary));
			for (int i=0;i<80;i++)
			{
				if (read_buffer[i] == '.')//strncmp(read_buffer[i],"46",1) == 0)
				{
					k++;
				}
				else
				{
					//read_buffer[i] = atoi(read_buffer[i]);// - 48;
					temporary[k] = temporary[k]*10 + read_buffer[i] - '0';//(atoi(read_buffer[i]));
				}
			}

			//temporary[3] = atoi(read_buffer[10]);
			timerCounter16bit = temporary[0];
			TCNT1 = temporary[1] + temporary[2];
			
			
			if (temporary[3] == 1)
			{
				state = ascent;
			}
			else if (temporary[3] == 2)
			{
				state = heating;
				timerCounter16bit = 45;
				TCNT1 = 0;					//(remember to change in timer.c  as well!)
			}
			else if (temporary[3] == 3)
			{
				state = cooling;
			}
			else if (temporary[3] == 4)
			{
				state = shutdown;
			}
			else //(temporary[3] == 0)
			{
				state = preflight;
			}
 			
		
			fat_close_file(fd);
			
			struct fat_dir_entry_struct file_entry2;
			fat_create_file(dd, "va.txt", &file_entry2);
		
			struct fat_file_struct* fd2 = fat_open_file(fs, &file_entry2);
		
			int32_t file_pos2 = 0;
			fat_seek_file(fd2, &file_pos2, FAT_SEEK_SET);
			
			   		
			char buffer[80]; //54
			int n;

			//n = sprintf(buffer,"S.%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d.E\r\n",read_buffer[0],read_buffer[1],read_buffer[2],read_buffer[3],read_buffer[4],
			//read_buffer[5],read_buffer[6],read_buffer[7],read_buffer[8],read_buffer[9],read_buffer[10],read_buffer[11],read_buffer[12],read_buffer[13],read_buffer[14]);

			n = sprintf(buffer,"S.%d.%d.%d.%d.E\r\n",temporary[0],temporary[1],temporary[2],temporary[3]);
			
			fat_write_file(fd2, buffer, n);
		
			fat_close_file(fd2);
		
		/* close directory */
		fat_close_dir(dd);

		/* close file system */
		fat_close(fs);

		/* close partition */
		partition_close(partition);
		  
		return 0;
	}
		